package com.example.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * @author chentao
 * @version 1.0
 * @description: 动态线程池
 * @date 2025/10/16 22:24
 */
public class DynamicThreadPool {

    Logger logger = LoggerFactory.getLogger(DynamicThreadPool.class);

    // 线程池名称
    private String poolName = "default";

    // 线程池核心线程数
    private int corePoolSize = 2;

    // 线程池最大线程数
    private int maxPoolSize = 15;

    // 线程池存活时间
    private int keepAliveTime = 60;

    // 线程池监控线程池大小
    private int monitorCorePoolSize = 10;

    // 线程池监控周期
    private int monitorPeriod = 5;

    // 线程池使用率超过75%时，线程池扩容
    private Double border = 0.75;

    //线程池扩容比率 正负
    private Double increaseRate = 0.25;

    // 线程池队列容量
    private int capacity = 20;

    private LinkedBlockingQueue<Runnable> failedWorkQueue = new LinkedBlockingQueue<>();

    private ThreadPoolExecutor threadPoolExecutor = null;

    private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = null;

    public DynamicThreadPool() {
    }

    public DynamicThreadPool(String poolName) {
        this.poolName = poolName;
    }

    public DynamicThreadPool(String poolName, int corePoolSize, int maxPoolSize, int keepAliveTime) {
        this.poolName = poolName;
        this.corePoolSize = corePoolSize;
        this.maxPoolSize = maxPoolSize;
        this.keepAliveTime = keepAliveTime;
    }

    public DynamicThreadPool(String poolName, int corePoolSize, int maxPoolSize, int keepAliveTime, Double border, Double increaseRate, int capacity) {
        this.poolName = poolName;
        this.corePoolSize = corePoolSize;
        this.maxPoolSize = maxPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.border = border;
        this.increaseRate = increaseRate;
        this.capacity = capacity;
    }

    public DynamicThreadPool(int corePoolSize, int maxPoolSize, int keepAliveTime, Double border, Double increaseRate, int capacity) {
        this.corePoolSize = corePoolSize;
        this.maxPoolSize = maxPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.border = border;
        this.increaseRate = increaseRate;
        this.capacity = capacity;
    }

    public void start() {
        this.threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingQueue<>(capacity), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable runnable) {
                return new Thread(runnable, poolName + "-thread-" + Thread.currentThread().getId());
            }
        });
        this.scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(monitorCorePoolSize);
        this.scheduledThreadPoolExecutor.scheduleAtFixedRate(new DynamicThreadPoolMonitor(), 0, monitorPeriod, TimeUnit.SECONDS);
        this.scheduledThreadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Runnable runnable = failedWorkQueue.take();
                        execute(runnable);
                    } catch (Exception e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });
    }

    public void execute(Runnable command) {
        try {
            threadPoolExecutor.execute(command);
        } catch (RejectedExecutionException e) {
            failedWorkQueue.offer(command);
        }
    }

    public void stop() {
        this.threadPoolExecutor.shutdown();
        scheduledThreadPoolExecutor.shutdown();
    }

    class DynamicThreadPoolMonitor implements Runnable {
        @Override
        public void run() {
            if (threadPoolExecutor.getQueue().isEmpty()) {
                int newSize = (int) (threadPoolExecutor.getMaximumPoolSize() * (1 - increaseRate));
                if (newSize > corePoolSize) {
                    threadPoolExecutor.setMaximumPoolSize(newSize);
                }
            }
            if (failedWorkQueue.size() >= threadPoolExecutor.getMaximumPoolSize() * border) {
                int newSize = (int) Math.ceil(threadPoolExecutor.getMaximumPoolSize() * (1 + increaseRate));
                threadPoolExecutor.setMaximumPoolSize(newSize);
            }
            logger.info("线程池: {} 活跃线程: {}/{}，池中线程: {}，队列任务: {}，备用队列: {}", poolName, threadPoolExecutor.getActiveCount(), threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getPoolSize(), threadPoolExecutor.getQueue().size(), failedWorkQueue.size());
        }
    }
}